import networkx as nx
import Recommender.UserBasedCF as cf
import matplotlib.pyplot as plt
import time
from Core.Config import *
config = Config()
database = config.DataBase()
realtime = config.RealTime(db=1)


def GetUserBasedCF():
    useractions = database.find("Recommender", "UserAction_Plus", query={"limit": 1000})
    train = {}
    for useraction in useractions:
        user = useraction["userpin"]
        article = useraction["article_id"]
        score = useraction["type"]
        if score == "COLLECT":
            score = 1
        elif score == "LIKE":
            score = 1
        elif score == "DISLIKE":
            score = -1
        else:
            score = 0
        if user not in train:
            train[user] = {}
            train[user][article] = score
        else:
            train[user][article] = score

    UserSimilarity = cf.UserSimilarity(train)

    all_users = []

    for user in UserSimilarity:
        all_users.append(user)
        for i in UserSimilarity[user]:
            related_user = i
            related_para = UserSimilarity[user][related_user]

    g = nx.Graph()
    g.clear()  # 将图上元素清空

    g.add_nodes_from(all_users)

    for user in UserSimilarity:
        for i in UserSimilarity[user]:
            related_user = i
            related_para = UserSimilarity[user][related_user]
            g.add_edge(user, related_user, weight=related_para)


    elarge = [(u, v) for (u, v, d) in g.edges(data=True) if d['weight'] > 0.75]
    esmall = [(u, v) for (u, v, d) in g.edges(data=True) if d['weight'] <= 0.75 and d['weight']>= 0.5]
    pos = nx.spring_layout(g)  # positions for all nodes
    nx.draw_networkx_nodes(g, pos, node_size=10)
    nx.draw_networkx_edges(g, pos, edgelist=elarge, width=1)
    nx.draw_networkx_edges(g, pos, edgelist=esmall, width=1, alpha=0.5, edge_color='b', style='dashed')
    #nx.draw_networkx_labels(g, pos, font_size=20, font_family='sans-serif')

    plt.show()


def GetRedits():

    a = realtime.GetHashObjects("Article_Tags_Corpus4_LDA_90_Batch1")
    debug = 1




def PersonalRank(G, alpha, root, max_step):
    #G：二分图
    #alpha: 随机游走的概率
    #root：游走的初始节点
    #max_step；最大走动步数
    rank = dict()
    rank = {x:0 for x in G.keys()}
    rank[root] = 1
    #开始迭代

    for k in range(max_step):
        tmp = {x:0 for x in G.keys()}
        #取节点i和它的出边尾节点集合ri
        for i, ri in G.items():  #i是顶点。ri是与其相连的顶点极其边的权重
            #取节点i的出边的尾节点j以及边E(i,j)的权重wij, 边的权重都为1，在这不起实际作用
            for j, wij in ri.items():   #j是i的连接顶点，wij是权重
                #i是j的其中一条入边的首节点，因此需要遍历图找到j的入边的首节点，
                #这个遍历过程就是此处的2层for循环，一次遍历就是一次游走
                tmp[j] += alpha * rank[i] / (1.0 * len(ri))
                a =  tmp[j]
        #我们每次游走都是从root节点出发，因此root节点的权重需要加上(1 - alpha)
        #在《推荐系统实践》上，作者把这一句放在for j, wij in ri.items()这个循环下，我认为是有问题。
        tmp[root] += (1 - alpha)
        rank = tmp

        #输出每次迭代后各个节点的权重
        if k< 99:
            continue
        print (time.strftime('%H:%M:%S',time.localtime(time.time())),"[",root ,"]:  ",end="")
        order = sorted(rank.items(), key=lambda x: x[1],reverse = True)
        result = []
        for i in range(len(order)):
            if order[i][0] in user_list or order[i][0] in user_list[user]: #
                continue
            print (order[i][0],": " ,order[i][1] ," ",end="")
            if order[i][1] > 0 and len(result) < 21:
                result.append([order[i][0], order[i][1]])

        print("")



    followersDoc = {}

    followersDoc["recommendations"] = result
    followersDoc["Key"] = user
    followersDoc["Userpin"] = user
    #print(followersDoc)
    database.upsert("Recommender", "Re_of_Graph", {"Key": followersDoc["Key"]}, followersDoc)
    return (result)
#GetUserBasedCF()

#GetRedits()
useractions = database.find("Recommender", "UserAction_Plus", query={"limit": 80000})
train = {}
user_list = {}
article_list = {}
for useraction in useractions:
    user = useraction["userpin"]
    article = useraction["article_id"]
    score = useraction["type"]
    if score == "COLLECT":
        score = 1
    elif score == "LIKE":
        score = 1
    elif score == "DISLIKE":
        score = -1
    else:
        score = 0
    if user not in train:
        train[user] = {}
        train[user][article] = score
        user_list[user]  = {}
        user_list[user][article] = score
    else:
        train[user][article] = score
        user_list[user][article] = score
    if article not in train:
        train[article] = {}
        train[article][user] = score
        article_list[article] = {}
        article_list[article][user] = score
    else:
        train[article][user] = score
        article_list[article][user] = score
count = 0
for article in article_list:
    count += 1
print (count)
count = 0
for user in user_list:
    count += 1
print(count)

Result = {}
for user in user_list:
    result = PersonalRank(train, 0.85, user, 100)



